class Budget {
    Float expectedTotalIncome = 0.0
    Float knownTotalIncome = 0.0
    Float knownVariableCost = 0.0
    Float lastYearBalance = 0.0
    Integer year = 2009
    Project project
    Float itCost = 16000.0;
    Float incomingBalance = 0.0;
    //To save last years balance to avoid looking up chains    
    Boolean lastYearBalanceSet = false

    static belongsTo = Project
    static hasMany = [variableCosts: VariableCost]
    
    static constraints = {
        expectedTotalIncome(min:0.0f)
        knownTotalIncome(min:0.0f)
        knownVariableCost(min:0.0f)
        project(nullable:false)
        itCost(min:0.0f,nullable:false)
        incomingBalance(min:0.0f,nullable:false)
    }
    

    //Income know up until now and expected for the rest of the budget
    public Float calcTotalIncome(){
        return (expectedTotalIncome + knownTotalIncome);
    }
    public Float calcTotalCost(){
        return calcTotalVariableCost() + calcTotalFixedCost ()
    }

    //Variable costs know up until now and expected for the rest of the budget
    //USED TO CALCULATE KNOWN VARIABLE COST + SUM DETAILED EXPECTED VARIABLE COST
    public Float calcTotalVariableCost(){        
        return knownVariableCost + this.calcExpectedVariableCost()
    }


    //Know fixed income for the budget
    public Float calcTotalFixedCost(){
        Float sum=0
        if(DBConnection.isConnectionStarted()){
            //println("project here:::: "+project )
            def whoalist = DBConnection.getWhoaList(project)
            //println("whoalist:"+whoalist)
            for(Whoa works: whoalist)
            {
                sum += works.calculateCost()
            }
        }else{
            for(Whoa works: project.amountOfHour)
            {
                sum += works.calculateCost()
            }
        }
        
        return sum
    }

    //Expected variable costs for the rest of the budget
    //USED TO SUM THE DETAILED EXPECTED VARIABLE COST
    public Float calcExpectedVariableCost(){
        Float sum =0.0
        for(VariableCost cost : variableCosts)
        {
            sum+=cost.amount
        }
        return sum
    }

    //The balance taking into account previous year balances
    public Float calcBalance(){
        return calcTotalIncome() - calcTotalVariableCost() -calcTotalFixedCost() + calcBalanceLastYear()
    }

    //Returns the saved value of calculated balances if possible otherwise asks previous year after its balance (ad infinitum until he non existant budget is "discovered")
    public Float calcBalanceLastYear(){
        if(this.project == null) // then the budget has no knowledge which project it belongs to
        {
//            println("used default value for last year, no link to project exists")
            return 0 //TODO FIND AND SET INSTEAD OF ASSUMING 0
        }

        if(!project.budgetExists(this.year-1))
        {
//            println("Last budget counted:"+this.year)
            return 0
        }
            

        //If the previous year has already been calculated (prevents it from always going though all years)
        if(!lastYearBalanceSet)
        {
            // TODO set to figure out if bugdet is from last year or not
            Date d = new Date()
            if(d.getYear()>=year){
                throw new Exception("Tried to calculate balance of a non finished year:"+year+1900)
            }

            Budget lastYearBudget = project.budget(this.year-1)
//            println("lastYearBalanceSet:"+this.year)
            lastYearBalanceSet = true
            if(lastYearBudget == null)
                lastYearBalance = 0
            else
                lastYearBalance = lastYearBudget.calcBalance()
                
            this.save()
//            println("lastYearBalance:"+this.lastYearBalance+" saved")
        }
        return lastYearBalance
    }

    /////////////////FOR DISPLAY CALCULATIONS///////////////////

    public Float sumSalaryCost() {
       Float sum=0
        if(DBConnection.isConnectionStarted()){
            //println("project here:::: "+project )
            def whoalist = DBConnection.getWhoaList(project)
            //println("whoalist:"+whoalist)
            for(Whoa works: whoalist)
            {
                sum += works.costOneEmployee()
            }
        }else{
            for(Whoa works: project.amountOfHour)
            {
                sum += works.costOneEmployee()
            }
        }
        return sum
    }

    public Float sumDriftCost() {
        Float sum=0
        if(DBConnection.isConnectionStarted()){
            //println("project here:::: "+project )
            def whoalist = DBConnection.getWhoaList(project)
            //println("whoalist:"+whoalist)
            for(Whoa works: whoalist)
            {
                sum += works.driftCost()
            }
        }else{
            for(Whoa works: project.amountOfHour)
            {
                sum += works.driftCost()
            }
        }
        return sum
    }

    public Float feeRentCost() {
        Float variableCost = 0

        for (VariableCost i in variableCosts ) {
            if (i.category.name.equals('Travel') && i.amount>0) {
                //println("feeRent:"+i.amount)
               variableCost = i.amount
               break;
            }
        }
        return 0.17*(this.sumDriftCost()+this.sumSalaryCost()+variableCost) //When 0.05 and when 0.17?
    }
    public Float oHCost() {
        
        Float variableCost = 0

        for (VariableCost i in variableCosts ) {
            if (i.category.name.equals('Travel') && i.amount>0) {
                //println("OHCost:"+i.amount)
               variableCost = i.amount
               break;
            }
        }

        return 0.40*(this.sumDriftCost()+this.sumSalaryCost()+variableCost)
    }

    public Float sumOfCost() {
        
        Float variableCost = 0

        for (VariableCost i in variableCosts ) {
            if (i.category.name.equals('Travel')&& i.amount>0) {
                //println("SumOFCost:"+i.amount)
               variableCost = i.amount
               break;
            }
        }
        
        return (this.sumSalaryCost()+this.sumDriftCost()+this.feeRentCost()+this.oHCost()+itCost+variableCost)
    }

    public Float calculationResult() {
        return (this.calcTotalIncome()-this.sumOfCost())
    }

   

    public String toString(){
        return "Budget:"+id+", year:"+this.year.toString()
    }

    public Float calcOutgoingBalance(){
        return (incomingBalance+calculationResult());
    }
}
